/*
CTC协议主控端模块,卡头使用此模块进行数据处理
根据https://gitee.com/GMSA/CTC文档定义
具体使用见CTCMasterDemo.c文件
*/
#ifndef CTC_MASTER_H
#define CTC_MASTER_H
#include "CTCClient.h"


#define CTC_MASTER_VERSION 1 // CTC主控端版本号
#define CTC_MASTER_PRODUCTID 0 // 主控端产品ID,V1.0版本为0

/// @brief 初始化CTC主控端
/// @note 需要在程序初始化时调用,会初始化发送和接收缓冲区,并设置初始状态为尝试连接状态
/// @note 需要在主循环中每隔1ms调用CTC_Master_Loop1ms()函数
/// @param  无
void CTC_Master_Init(void);

/// @brief 主循环处理函数
/// @note 根据当前状态进行数据处理,发现发送缓冲区有数据就发送数据,发现接收缓冲区有数据就处理数据
/// @note 先判断缓冲区有要发送的数据就先发送,发送完成等待收到ACK后回调发送结果回调函数,如果发送超时未收到ACK就重发,重发超过最大次数就回调发送结果回调函数告知发送失败,如果连续9次都是超时将标记为断开连接,缓冲区的内容分两段先读取第一个字节为长度,然后就读取这个长度的数据调用CTC_Master_SetSendDataCallback对应的函数发送出去,每次仅发送一条报文,并保证与上一次发送至少间隔CTC_MIN_FRAME_TIME毫秒.
/// @note 如果有接收但未处理的数据就处理接收数据,处理数据时从头读取缓冲区中有效数据并按协议帧进行解析,如果有完整的数据帧并校验通过就回应ACK并调用指令对应的回调函数,如果接收的数据是重复的就回应ACK但不调用回调函数,判断为重复数据是根据事务ID进行判断,如果事务ID与上次处理的相同就认为是重复数据,如果发现不符合协议格式或校验失败就忽略此数据,并发送ACK告诉对方具体错误.
/// @note 需要在主循环中每1ms调用一次
/// @param  无
void CTC_Master_Loop1ms(void);

/// @brief 串口收到数据需要推送到此函数
/// @note 需要在串口接收中断中调用
/// @param data 接收到的数据指针
/// @param len 数据长度
void CTC_Master_ReceiveData(uint8_t* data, uint16_t len);

/// @brief 设置当前状态
/// @param state 当前设备状态,0=正常可用,1=等待配网,2=连接门店服务异常,3=网络无法连接,4=正在联网
void CTC_Master_SetMasterState(uint8_t state);

/// @brief 设置发送数据回调函数
/// @param callback 回调函数指针    
void CTC_Master_SetSendDataCallback(CTC_SendDataCallback callback);

/// @brief 设置Slave设备状态变化回调函数
/// @param callback 回调函数指针
void CTC_Master_SetSlaveStateChangeCallback(CTC_ConnStateChangeCallback callback);

/// @brief 设置数据发送结果回调函数
/// @param callback 回调函数指针
void CTC_Master_SetDataSendResultCallback(CTC_MsgSendCallback callback);

/// @brief 获取Slave端设备状态
/// @return 返回Slave端设备状态,如果未握手或未连接则返回CTC_STATE_UNKNOWN
uint8_t CTC_Master_GetSlaveDeviceState(void);

/// @brief 获取Slave端是否可消费
/// @return 返回Slave端设备可消费状态,1=不可消费,0=可消费,如果未握手或未连接则返回1
uint8_t CTC_Master_IsSlaveConsumable(void);

/// @brief 获取连接状态
/// @return 返回当前连接状态,参考CTC_ClientConnState
CTC_ClientConnState CTC_Master_GetConnectState(void);

/// @brief 获取离线时间(秒)
/// @return 返回当前离线时间,单位秒,如果在线返回0
uint32_t CTC_Master_GetOfflineTime(void);

/// @brief 获取重新连接次数
/// @return 返回当前重新连接次数
uint16_t CTC_Master_GetReConnectTimes(void);

/// @brief 获取总接收字节数
/// @return 返回总接收字节数
uint32_t CTC_Master_GetTotalReceivedBytes(void);

/// @brief 获取总发送字节数
/// @return 返回总发送字节数
uint32_t CTC_Master_GetTotalSentBytes(void);

/// @brief 获取总接收正确消息数
/// @return 返回总接收正确消息数
uint32_t CTC_Master_GetTotalReceivedMsgCount(void);

/// @brief 获取总发送正确消息数
/// @return 返回总发送正确消息数
uint32_t CTC_Master_GetTotalSentMsgCount(void);

/// @brief 获取总接收错误消息数
/// @return 返回总接收错误消息数
uint32_t CTC_Master_GetTotalReceivedErrorMsgCount(void);

/// @brief 获取当前连接的设备ID
/// @param deviceId 指向存储设备ID的指针,长度16字节
/// @return 0=已连接并且获取到了设备ID,其他值表示未连接或未获取到设备ID
uint8_t CTC_Master_GetSlaveDeviceId(uint8_t* deviceId);

/// @brief 设置Master端的设备ID
/// @param deviceId 指向存储设备ID的指针,长度16字节
void CTC_Master_SetDeviceId(const uint8_t* deviceId);

/// @brief 获取发送缓冲区数据长度
/// @return 返回发送缓冲区数据长度
uint16_t CTC_Master_GetSendBufferDataLength(void);

/// @brief 获取发送缓冲区空闲长度
/// @return 返回发送缓冲区空闲长度
uint16_t CTC_Master_GetSendBufferFreeLength(void);

/// @brief 获取接收缓冲区数据长度
/// @return 返回接收缓冲区数据长度
uint16_t CTC_Master_GetReceiveBufferDataLength(void);

/// @brief 获取接收缓冲区空闲长度
/// @return 返回接收缓冲区空闲长度
uint16_t CTC_Master_GetReceiveBufferFreeLength(void);

/// @brief 获取Slave端支持的CTC协议版本
/// @return 返回Slave端支持的CTC协议版本,如果未握手或未连接则返回0
uint16_t CTC_Master_GetSlaveCTCVersion(void);

/// @brief 打印过程的统计数据
void CTC_Master_PrintStatistics(void);


//抄表业务指令的处理----------------------------------------------------------------

/// @brief 发送抄表指令
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendReadMeterCommand(void);

/// @brief 抄表结果回调函数
/// @param msg 指向抄表结果消息结构体指针
typedef void (*CTC_Master_ReadMeterCallback)(const CTC_MeterDataRspMsgV1* msg);

/// @brief 设置抄表结果回调函数
/// @param callback 回调函数指针
void CTC_Master_SetReadMeterCallback(CTC_Master_ReadMeterCallback callback);


///投币业务指令的处理----------------------------------------------------------------

/// @brief 发送投币指令
/// @note 投币指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @note 如果对方有回应会在CTC_Master_SetCoinInCallback设置的回调函数中返回投币结果
/// @param msg 指向投币消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendCoinInCommand(const CTC_CoinInMsgV1* msg);

/// @brief 投币结果回调函数
/// @param msg 指向投币应答消息结构体指针
typedef void (*CTC_Master_CoinInCallback)(const CTC_CoinInRspMsgV1* msg);

/// @brief 设置投币结果回调函数
/// @param callback 投币结果回调函数指针
void CTC_Master_SetCoinInRspCallback(CTC_Master_CoinInCallback callback);

//通道选择业务指令的处理----------------------------------------------------------------

/// @brief 发送通道选择指令
/// @note 此指令没有专门的应答,指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @param msg 指向通道选择消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendSelectChannelCommand(const CTC_ChannelSelMsgV1* msg);

//查询与设置单价业务指令的处理----------------------------------------------------------------

/// @brief 发送查询单价指令
/// @note 指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @note 如果对方有回应会在CTC_Master_SetQueryCoinPriceCallback设置的回调函数中返回查询结果
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendQueryCoinPriceCommand(void);

/// @brief 查询单价结果回调函数
/// @param msg 指向查询单价消息结构体指针
typedef void (*CTC_Master_QueryCoinPriceCallback)(const CTC_CoinPriceMsgV1* msg);

/// @brief 设置查询单价结果回调函数
/// @param callback 查询单价结果回调函数指针
void CTC_Master_SetQueryCoinPriceCallback(CTC_Master_QueryCoinPriceCallback callback);

/// @brief 发送设置单价指令
/// @note 指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @note 此指令没有专门的应答
/// @param msg 指向设置单价消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendSetCoinPriceCommand(const CTC_CoinPriceMsgV1* msg);

//氛围控制业务指令的处理----------------------------------------------------------------

/// @brief 氛围事件回调类型
/// @param msg 指向氛围控制消息结构体指针
typedef void (*CTC_Master_AtmosphereEventCallback)(const CTC_AtmosphereDataV1* msg);

/// @brief 设置氛围事件回调函数
/// @param callback 回调函数指针
void CTC_Master_SetAtmosphereEventCallback(CTC_Master_AtmosphereEventCallback callback);

//游戏奖励事件回调----------------------------------------------------------------

/// @brief 游戏奖励事件回调类型
/// @param msg 指向游戏奖励消息结构体指针
typedef void (*CTC_Master_GameRewardEventCallback)(const CTC_RewardMsgV1* msg);
/// @brief 设置游戏奖励事件回调函数
/// @param callback 回调函数指针
void CTC_Master_SetGameRewardEventCallback(CTC_Master_GameRewardEventCallback callback);

//实物奖励业务指令的处理----------------------------------------------------------------
/// @brief 实物奖励回调类型
/// @param msg 指向实物奖励消息结构体指针
typedef void (*CTC_Master_PhysicalRewardCallback)(const CTC_PhysicalReportMsgV1* msg);
/// @brief 设置实物奖励回调函数
/// @param callback 回调函数指针
void CTC_Master_SetPhysicalRewardCallback(CTC_Master_PhysicalRewardCallback callback);


#endif // CTC_MASTER_H

